package com.zsd.android.glidelib.widget;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.BitmapRegionDecoder;
import android.graphics.Canvas;
import android.graphics.Matrix;
import android.graphics.Rect;
import android.support.annotation.Nullable;
import android.util.AttributeSet;
import android.util.Log;
import android.view.GestureDetector;
import android.view.MotionEvent;
import android.view.ScaleGestureDetector;
import android.view.View;
import android.widget.Scroller;

import java.io.IOException;
import java.io.InputStream;

public class NeBigView extends View implements GestureDetector.OnGestureListener,
        View.OnTouchListener, GestureDetector.OnDoubleTapListener {

    private final int MAX_SCALE_MULTIPLE = 2;
    private final Rect mRect;
    private final BitmapFactory.Options mOptions;
    private final GestureDetector mGestureDetector;
    private Scroller mScroller;
    private int mImageWidth;
    private int mImageHeight;
    private BitmapRegionDecoder mDecoder;
    private int mViewWidth;
    private int mViewHeight;
    private float mScale;
    private Bitmap mBitmap;
    private Matrix matrix;
    private ScaleGestureDetector mScaleGestureDetector;
    private float originalScale;
    private float centerX, centerY;

    public NeBigView(Context context) {
        this(context, null);
    }

    public NeBigView(Context context, @Nullable AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public NeBigView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        //第一步：设备bigView需要的成员变量
        mRect = new Rect();
        //内存复用
        mOptions = new BitmapFactory.Options();
        //手势识别
        mGestureDetector = new GestureDetector(context, this);
        //滚动类
        mScroller = new Scroller(context);
        //缩放手势
        mScaleGestureDetector = new ScaleGestureDetector(context, new ScaleGesture());
        setOnTouchListener(this);
        matrix = new Matrix();
    }

    /**
     * 第二步
     * 设置图片
     *
     * @param is
     */
    public void setImage(InputStream is) {
        //获取图片信息，不能将整张图片加载进内存
        mOptions.inJustDecodeBounds = true;
        BitmapFactory.decodeStream(is, null, mOptions);
        mImageWidth = mOptions.outWidth;
        mImageHeight = mOptions.outHeight;
        //开启复用
        mOptions.inMutable = true;
        //设置格式
        mOptions.inPreferredConfig = Bitmap.Config.RGB_565;
        mOptions.inJustDecodeBounds = false;
        //创建一个区域解码器
        try {
            mDecoder = BitmapRegionDecoder.newInstance(is, false);
        } catch (IOException e) {
            e.printStackTrace();
        }
        requestLayout();
    }

    /**
     * 第三步
     * 测量
     *
     * @param widthMeasureSpec
     * @param heightMeasureSpec
     */
    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        mViewWidth = getMeasuredWidth();
        mViewHeight = getMeasuredHeight();
        //确定图片加载的区域
//        mRect.left = 0;
//        mRect.top = 0;
//        mRect.right = mImageWidth;
//        //得到图片的宽度，就能根据View的宽度得到缩放因子
//        mScale = mViewWidth * 1.0f / mImageWidth;
//        mRect.bottom = (int) (mViewHeight / mScale);
        //---------------以上是没有加缩放手势之后的写法---------------------------

        //---------------以下是加了手势缩放之后的写法-----------------------------
        mRect.left = 0;
        mRect.top = 0;
        mRect.right = Math.min(mImageWidth, mViewWidth);
        mRect.bottom = Math.min(mImageHeight, mViewHeight);
        //再定义一个缩放因子
        originalScale = mViewWidth * 1.0f / mImageWidth;
        mScale = originalScale;
    }

    /**
     * 第四步
     * 画出具体内容
     *
     * @param canvas
     */
    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        if (mDecoder == null) {
            return;
        }
        //复用内存, 复用Bitmap必须跟即将解码的bitmap尺寸一样
        mOptions.inBitmap = mBitmap;
        mBitmap = mDecoder.decodeRegion(mRect, mOptions);
        float scale = mViewWidth * 1.0f / mRect.width();
//        matrix.setScale(mScale, mScale);
        matrix.setScale(scale, scale);
        canvas.drawBitmap(mBitmap, matrix, null);
    }

    /**
     * 第五步
     * 处理点击事件
     *
     * @param v
     * @param event
     * @return
     */
    @Override
    public boolean onTouch(View v, MotionEvent event) {
        //直接将事件传递给手势事件处理
        mGestureDetector.onTouchEvent(event);
        mScaleGestureDetector.onTouchEvent(event);
        return true;
    }

    /**
     * 第六步
     * 手按下去，处理事件
     *
     * @param e
     * @return
     */
    @Override
    public boolean onDown(MotionEvent e) {
        //如果移动没有停止，就强行停止
        if (!mScroller.isFinished()) {
            mScroller.forceFinished(true);
        }
        return true;
    }

    /**
     * 第七部
     * 处理滑动事件
     *
     * @param e1        开始事件，手指按下去获取坐标
     * @param e2        当前事件
     * @param distanceX x轴移动的距离
     * @param distanceY y轴移动的距离
     * @return
     */
    @Override
    public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
        //上下移动的时候，mRect需要改变现实区域
        mRect.offset((int) distanceX / 2, (int) distanceY / 2);
        //移动时，处理到达顶部和底部的情况
        if (mRect.bottom > mImageHeight) {
            mRect.bottom = mImageHeight;
            mRect.top = mImageHeight - (int) (mViewHeight / mScale);
        }
        if (mRect.top < 0) {
            mRect.top = 0;
            mRect.bottom = (int) (mViewHeight / mScale);
        }
        if (mRect.right > mImageWidth) {
            mRect.right = mImageWidth;
            mRect.left = mImageWidth - (int) (mViewWidth / mScale);
        }
        if (mRect.left < 0) {
            mRect.left = 0;
            mRect.right = (int) (mViewWidth / mScale);
        }
        invalidate();
        return false;
    }

    /**
     * 第八步
     * 处理惯性
     *
     * @param e1
     * @param e2
     * @param velocityX
     * @param velocityY
     * @return
     */
    @Override
    public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
//        mScroller.fling(0, mRect.top, 0, (int) -velocityY, 0, 0,
//                0, mImageHeight - (int) (mViewHeight / mScale));
        mScroller.fling(mRect.left, mRect.top, (int) -velocityX / 2, (int) -velocityY / 2, 0, mImageWidth - (int) (mViewWidth / mScale),
                0, mImageHeight - (int) (mViewHeight / mScale));
        return false;
    }

    /**
     * 第九步
     * 处理结果
     */
    @Override
    public void computeScroll() {
        super.computeScroll();
        if (mScroller.isFinished()) {
            return;
        }
        if (mScroller.computeScrollOffset()) {
            mRect.top = mScroller.getCurrY();
            mRect.bottom = mRect.top + (int) (mViewHeight / mScale);
            invalidate();
        }
    }

    @Override
    public void onShowPress(MotionEvent e) {

    }

    @Override
    public boolean onSingleTapUp(MotionEvent e) {
        return false;
    }

    @Override
    public void onLongPress(MotionEvent e) {

    }

    @Override
    public boolean onSingleTapConfirmed(MotionEvent e) {
        return false;
    }

    /**
     * 双击事件
     *
     * @param e
     * @return
     */
    @Override
    public boolean onDoubleTap(MotionEvent e) {
        if (mScale < originalScale * 1.3) {
            mScale = originalScale * MAX_SCALE_MULTIPLE;
        } else {
            mScale = originalScale;
        }
        mRect.right = mRect.left + (int) (mViewWidth / mScale);
        mRect.bottom = mRect.top + (int) (mViewHeight / mScale);
        //移动时，处理到达顶部和底部的情况
        if (mRect.bottom > mImageHeight) {
            mRect.bottom = mImageHeight;
            mRect.top = mImageHeight - (int) (mViewHeight / mScale);
        }
        if (mRect.top < 0) {
            mRect.top = 0;
            mRect.bottom = (int) (mViewHeight / mScale);
        }
        if (mRect.right > mImageWidth) {
            mRect.right = mImageWidth;
            mRect.left = mImageWidth - (int) (mViewWidth / mScale);
        }
        if (mRect.left < 0) {
            mRect.left = 0;
            mRect.right = (int) (mViewWidth / mScale);
        }
        centerX = e.getX();
        centerY = e.getY();
        invalidate();
        return true;
    }

    @Override
    public boolean onDoubleTapEvent(MotionEvent e) {
        return false;
    }

    /**
     * 处理缩放事件的回调
     */
    class ScaleGesture extends ScaleGestureDetector.SimpleOnScaleGestureListener {

        @Override
        public boolean onScale(ScaleGestureDetector detector) {
            float scale = mScale;
            scale += detector.getScaleFactor() - 1;
            if (scale <= originalScale) {
                scale = originalScale;
            } else if (scale > originalScale * MAX_SCALE_MULTIPLE) {
                scale = originalScale * MAX_SCALE_MULTIPLE;
            }
            mRect.right = mRect.left + (int) (mViewWidth / scale);
            mRect.bottom = mRect.top + (int) (mViewHeight / scale);
            mScale = scale;
            invalidate();
            return true;
        }
    }
}
